package cn.lngaosu.lwyd.module.integration.service.weixinarticleanalysis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.lngaosu.lwyd.framework.common.util.http.HttpUtils;
import cn.lngaosu.lwyd.module.infra.service.config.ConfigService;
import cn.lngaosu.lwyd.module.integration.dal.dataobject.weixinuseranalysis.WeixinUserSummaryDO;
import cn.lngaosu.lwyd.module.integration.enums.WeixinArticleAnalysisEnum;
import cn.lngaosu.lwyd.module.integration.service.apptoken.AppTokenService;
import cn.lngaosu.lwyd.module.system.dal.dataobject.webinterfacelog.WebinterfaceLogDO;
import cn.lngaosu.lwyd.module.system.dal.mysql.webinterfacelog.WebinterfaceLogMapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import cn.lngaosu.lwyd.module.integration.controller.admin.weixinarticleanalysis.vo.*;
import cn.lngaosu.lwyd.module.integration.dal.dataobject.weixinarticleanalysis.WeixinArticleAnalysisDO;
import cn.lngaosu.lwyd.module.integration.dal.dataobject.weixinarticleanalysis.WeixinArticleAnalysisSourceDO;
import cn.lngaosu.lwyd.framework.common.pojo.PageResult;
import cn.lngaosu.lwyd.framework.common.pojo.PageParam;
import cn.lngaosu.lwyd.framework.common.util.object.BeanUtils;

import cn.lngaosu.lwyd.module.integration.dal.mysql.weixinarticleanalysis.WeixinArticleAnalysisMapper;
import cn.lngaosu.lwyd.module.integration.dal.mysql.weixinarticleanalysis.WeixinArticleAnalysisSourceMapper;

import static cn.lngaosu.lwyd.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.lngaosu.lwyd.framework.common.util.collection.CollectionUtils.convertList;
import static cn.lngaosu.lwyd.framework.common.util.collection.CollectionUtils.diffList;
import static cn.lngaosu.lwyd.module.integration.enums.ErrorCodeConstants.*;

/**
 * 微信文章分析 Service 实现类
 *
 * @author 张恒
 */
@Service
@Validated
public class WeixinArticleAnalysisServiceImpl implements WeixinArticleAnalysisService {
    private static final Logger logger = LoggerFactory.getLogger(WeixinArticleAnalysisServiceImpl.class);

    @Resource
    private WeixinArticleAnalysisMapper weixinArticleAnalysisMapper;
    @Resource
    private WeixinArticleAnalysisSourceMapper weixinArticleAnalysisSourceMapper;
    @Resource
    private AppTokenService appTokenService;
    @Resource
    private ConfigService configService;
    @Resource
    private WebinterfaceLogMapper webinterfaceLogMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWeixinArticleAnalysis(WeixinArticleAnalysisSaveReqVO createReqVO) {
        // 插入
        WeixinArticleAnalysisDO weixinArticleAnalysis = BeanUtils.toBean(createReqVO, WeixinArticleAnalysisDO.class);
        weixinArticleAnalysisMapper.insert(weixinArticleAnalysis);

        // 插入子表
        createWeixinArticleAnalysisSourceList(weixinArticleAnalysis.getId(), createReqVO.getWeixinArticleAnalysisSources());
        // 返回
        return weixinArticleAnalysis.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateWeixinArticleAnalysis(WeixinArticleAnalysisSaveReqVO updateReqVO) {
        // 校验存在
        validateWeixinArticleAnalysisExists(updateReqVO.getId());
        // 更新
        WeixinArticleAnalysisDO updateObj = BeanUtils.toBean(updateReqVO, WeixinArticleAnalysisDO.class);
        weixinArticleAnalysisMapper.updateById(updateObj);

        // 更新子表
        updateWeixinArticleAnalysisSourceList(updateReqVO.getId(), updateReqVO.getWeixinArticleAnalysisSources());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWeixinArticleAnalysis(Long id) {
        // 校验存在
        validateWeixinArticleAnalysisExists(id);
        // 删除
        weixinArticleAnalysisMapper.deleteById(id);

        // 删除子表
        deleteWeixinArticleAnalysisSourceByAnalysisId(id);
    }

    @Override
        @Transactional(rollbackFor = Exception.class)
    public void deleteWeixinArticleAnalysisListByIds(List<Long> ids) {
        // 校验存在
        validateWeixinArticleAnalysisExists(ids);
        // 删除
        weixinArticleAnalysisMapper.deleteByIds(ids);
    
    // 删除子表
            deleteWeixinArticleAnalysisSourceByAnalysisIds(ids);
    }

    private void validateWeixinArticleAnalysisExists(List<Long> ids) {
        List<WeixinArticleAnalysisDO> list = weixinArticleAnalysisMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(WEIXIN_ARTICLE_ANALYSIS_NOT_EXISTS);
        }
    }

    private void validateWeixinArticleAnalysisExists(Long id) {
        if (weixinArticleAnalysisMapper.selectById(id) == null) {
            throw exception(WEIXIN_ARTICLE_ANALYSIS_NOT_EXISTS);
        }
    }

    @Override
    public WeixinArticleAnalysisDO getWeixinArticleAnalysis(Long id) {
        return weixinArticleAnalysisMapper.selectById(id);
    }

    @Override
    public PageResult<WeixinArticleAnalysisDO> getWeixinArticleAnalysisPage(WeixinArticleAnalysisPageReqVO pageReqVO) {
        return weixinArticleAnalysisMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（微信文章分析子表(按渠道区分)） ====================

    @Override
    public List<WeixinArticleAnalysisSourceDO> getWeixinArticleAnalysisSourceListByAnalysisId(Long analysisId) {
        return weixinArticleAnalysisSourceMapper.selectListByAnalysisId(analysisId);
    }

    @Override
    public void syncWeixinArticleSummary() {
        // 获取微信token
        String weixinToken = appTokenService.getWeixinToken();
        if (StringUtils.isEmpty(weixinToken)) {
            throw exception(WEIXIN_TOKEN_NOT_EXISTS);
        }

        // 接口配置
        String configValue = configService.getConfigValueByKey("weixinConfig");
        if (StringUtils.isEmpty(configValue)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        JSONObject configJo = JSONObject.parseObject(configValue);
        // 接口开关
        String onOff = configJo.getString("onOff");
        if (!"on".equals(onOff)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        // 获取图文群发每日数据地址
        String articleSummaryUrl = configJo.getString("articleSummaryUrl");
        articleSummaryUrl = articleSummaryUrl + "?access_token=" + weixinToken;

        // 构造请求参数（每天查询一次，默认查询前一天数据）
        LocalDate date = LocalDate.now().minusDays(1L);
        JSONObject params = new JSONObject();
        params.put("begin_date", date.toString());
        params.put("end_date", date.toString());

        WebinterfaceLogDO webinterfaceLogDO = new WebinterfaceLogDO();

        try {
            // 初始化图文群发每日数据接口日志数据（默认成功）
            webinterfaceLogDO.setInterfaceSystemName("微信公众号");
            webinterfaceLogDO.setInterfaceName("获取图文群发每日数据");
            webinterfaceLogDO.setInterfaceUrl(articleSummaryUrl);
            webinterfaceLogDO.setInterfaceRequestMethod("POST");
            webinterfaceLogDO.setInterfaceParam(JSONObject.toJSONString(params));
            webinterfaceLogDO.setInterfaceStatus("成功");
            webinterfaceLogMapper.insert(webinterfaceLogDO);

            // 获取图文群发每日数据
            String articleSummaryResult = HttpUtils.post(articleSummaryUrl, new HashMap<>(), JSONObject.toJSONString(params));
            // 解析接口结果
            JSONObject articleSummaryResultJo = JSONObject.parseObject(articleSummaryResult);
            Integer articleSummaryErrcode = articleSummaryResultJo.getInteger("errcode");
            if (ObjectUtils.isNotEmpty(articleSummaryErrcode)) {
                webinterfaceLogDO.setInterfaceStatus("失败");
                webinterfaceLogDO.setInterfaceErrorInfo(articleSummaryResult);
                webinterfaceLogMapper.updateById(webinterfaceLogDO);
                return;
            }
            webinterfaceLogDO.setInterfaceErrorInfo(articleSummaryResult);
            webinterfaceLogMapper.updateById(webinterfaceLogDO);

            // 处理接口数据
            JSONArray articleSummaryJa = articleSummaryResultJo.getJSONArray("list");
            List<WeixinArticleAnalysisDO> articleAnalysisDOS = BeanUtils.toBean(articleSummaryJa, WeixinArticleAnalysisDO.class);
            articleAnalysisDOS.forEach(o -> {
                o.setDataTypeCode(WeixinArticleAnalysisEnum.GET_ARTICLE_SUMMARY.getType());
                o.setDataType(WeixinArticleAnalysisEnum.GET_ARTICLE_SUMMARY.getName());
            });
            LambdaQueryWrapper<WeixinArticleAnalysisDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(WeixinArticleAnalysisDO::getRefDate, date)
                    .eq(WeixinArticleAnalysisDO::getDataTypeCode, WeixinArticleAnalysisEnum.GET_ARTICLE_SUMMARY.getType());
            weixinArticleAnalysisMapper.deleteAbsolute(queryWrapper);
            weixinArticleAnalysisMapper.insert(articleAnalysisDOS);
        } catch (Exception e) {
            webinterfaceLogDO.setInterfaceStatus("失败");
            webinterfaceLogDO.setInterfaceErrorInfo(e.getMessage());
            webinterfaceLogMapper.updateById(webinterfaceLogDO);
            logger.error("微信公众号【获取图文群发每日数据】接口失败！", e);
        }
    }

    @Override
    public void syncWeixinArticleUserread() {
        // 获取微信token
        String weixinToken = appTokenService.getWeixinToken();
        if (StringUtils.isEmpty(weixinToken)) {
            throw exception(WEIXIN_TOKEN_NOT_EXISTS);
        }

        // 接口配置
        String configValue = configService.getConfigValueByKey("weixinConfig");
        if (StringUtils.isEmpty(configValue)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        JSONObject configJo = JSONObject.parseObject(configValue);
        // 接口开关
        String onOff = configJo.getString("onOff");
        if (!"on".equals(onOff)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        // 获取图文统计数据地址
        String articleUserreadUrl = configJo.getString("articleUserreadUrl");
        articleUserreadUrl = articleUserreadUrl + "?access_token=" + weixinToken;

        // 构造请求参数（每天查询一次，默认查询前一天数据）
        LocalDate date = LocalDate.now().minusDays(1L);
        JSONObject params = new JSONObject();
        params.put("begin_date", date.toString());
        params.put("end_date", date.toString());

        WebinterfaceLogDO webinterfaceLogDO = new WebinterfaceLogDO();

        try {
            // 初始化图文统计数据接口日志数据（默认成功）
            webinterfaceLogDO.setInterfaceSystemName("微信公众号");
            webinterfaceLogDO.setInterfaceName("获取图文统计数据");
            webinterfaceLogDO.setInterfaceUrl(articleUserreadUrl);
            webinterfaceLogDO.setInterfaceRequestMethod("POST");
            webinterfaceLogDO.setInterfaceParam(JSONObject.toJSONString(params));
            webinterfaceLogDO.setInterfaceStatus("成功");
            webinterfaceLogMapper.insert(webinterfaceLogDO);

            // 获取图文统计数据
            String articleUserreadResult = HttpUtils.post(articleUserreadUrl, new HashMap<>(), JSONObject.toJSONString(params));
            // 解析接口结果
            JSONObject articleUserreadResultJo = JSONObject.parseObject(articleUserreadResult);
            Integer articleUserreadErrcode = articleUserreadResultJo.getInteger("errcode");
            if (ObjectUtils.isNotEmpty(articleUserreadErrcode)) {
                webinterfaceLogDO.setInterfaceStatus("失败");
                webinterfaceLogDO.setInterfaceErrorInfo(articleUserreadResult);
                webinterfaceLogMapper.updateById(webinterfaceLogDO);
                return;
            }
            webinterfaceLogDO.setInterfaceErrorInfo(articleUserreadResult);
            webinterfaceLogMapper.updateById(webinterfaceLogDO);

            // 处理接口数据
            // 子表数据
            JSONArray articleUserreadJa = articleUserreadResultJo.getJSONArray("list");
            List<WeixinArticleAnalysisSourceDO> articleAnalysisSourceDOS = BeanUtils.toBean(articleUserreadJa, WeixinArticleAnalysisSourceDO.class);
            articleAnalysisSourceDOS.forEach(o -> {
                o.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_READ.getType());
                o.setDataType(WeixinArticleAnalysisEnum.GET_USER_READ.getName());
            });
            // 主表数据（userSource为99999999代表全部数据）
            WeixinArticleAnalysisSourceDO weixinArticleAnalysisSourceDO = articleAnalysisSourceDOS.stream().filter(o -> ObjectUtils.isNotEmpty(o.getUserSource()) && o.getUserSource() == 99999999).collect(Collectors.toList()).get(0);
            WeixinArticleAnalysisSaveReqVO saveReqVO = BeanUtils.toBean(weixinArticleAnalysisSourceDO, WeixinArticleAnalysisSaveReqVO.class);
            // 子表数据（userSource不为99999999的数据）
            List<WeixinArticleAnalysisSourceDO> subDOS = articleAnalysisSourceDOS.stream().filter(o -> ObjectUtils.isNotEmpty(o.getUserSource()) && o.getUserSource() != 99999999).collect(Collectors.toList());
            saveReqVO.setWeixinArticleAnalysisSources(subDOS);

            this.createWeixinArticleAnalysis(saveReqVO);
        } catch (Exception e) {
            webinterfaceLogDO.setInterfaceStatus("失败");
            webinterfaceLogDO.setInterfaceErrorInfo(e.getMessage());
            webinterfaceLogMapper.updateById(webinterfaceLogDO);
            logger.error("微信公众号【获取图文统计数据】接口失败！", e);
        }
    }

    @Override
    public void syncWeixinArticleUserreadhour() {
        // 获取微信token
        String weixinToken = appTokenService.getWeixinToken();
        if (StringUtils.isEmpty(weixinToken)) {
            throw exception(WEIXIN_TOKEN_NOT_EXISTS);
        }

        // 接口配置
        String configValue = configService.getConfigValueByKey("weixinConfig");
        if (StringUtils.isEmpty(configValue)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        JSONObject configJo = JSONObject.parseObject(configValue);
        // 接口开关
        String onOff = configJo.getString("onOff");
        if (!"on".equals(onOff)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        // 获取图文统计分时数据地址
        String articleUserreadhourUrl = configJo.getString("articleUserreadhourUrl");
        articleUserreadhourUrl = articleUserreadhourUrl + "?access_token=" + weixinToken;

        // 构造请求参数（每天查询一次，默认查询前一天数据）
        LocalDate date = LocalDate.now().minusDays(1L);
        JSONObject params = new JSONObject();
        params.put("begin_date", date.toString());
        params.put("end_date", date.toString());

        WebinterfaceLogDO webinterfaceLogDO = new WebinterfaceLogDO();

        try {
            // 初始化图文统计分时数据接口日志数据（默认成功）
            webinterfaceLogDO.setInterfaceSystemName("微信公众号");
            webinterfaceLogDO.setInterfaceName("获取图文统计分时数据");
            webinterfaceLogDO.setInterfaceUrl(articleUserreadhourUrl);
            webinterfaceLogDO.setInterfaceRequestMethod("POST");
            webinterfaceLogDO.setInterfaceParam(JSONObject.toJSONString(params));
            webinterfaceLogDO.setInterfaceStatus("成功");
            webinterfaceLogMapper.insert(webinterfaceLogDO);

            // 获取图文统计分时数据
            String articleUserreadhourResult = HttpUtils.post(articleUserreadhourUrl, new HashMap<>(), JSONObject.toJSONString(params));
            // 解析接口结果
            JSONObject articleUserreadhourResultJo = JSONObject.parseObject(articleUserreadhourResult);
            Integer articleUserreadhourErrcode = articleUserreadhourResultJo.getInteger("errcode");
            if (ObjectUtils.isNotEmpty(articleUserreadhourErrcode)) {
                webinterfaceLogDO.setInterfaceStatus("失败");
                webinterfaceLogDO.setInterfaceErrorInfo(articleUserreadhourResult);
                webinterfaceLogMapper.updateById(webinterfaceLogDO);
                return;
            }
            webinterfaceLogDO.setInterfaceErrorInfo(articleUserreadhourResult);
            webinterfaceLogMapper.updateById(webinterfaceLogDO);

            // 处理接口数据
            JSONArray articleUserreadhourJa = articleUserreadhourResultJo.getJSONArray("list");
            List<WeixinArticleAnalysisSourceDO> articleAnalysisSourceDOS = BeanUtils.toBean(articleUserreadhourJa, WeixinArticleAnalysisSourceDO.class);
            articleAnalysisSourceDOS.forEach(o -> {
                o.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_READHOUR.getType());
                o.setDataType(WeixinArticleAnalysisEnum.GET_USER_READHOUR.getName());
            });
            // 按小时分组
            Map<Integer, List<WeixinArticleAnalysisSourceDO>> listMap = articleAnalysisSourceDOS.stream().collect(Collectors.groupingBy(WeixinArticleAnalysisSourceDO::getRefHour, LinkedHashMap::new, Collectors.toList()));
            listMap.forEach((key, value) -> {
                // 主表数据（userSource为99999999代表全部数据）
                WeixinArticleAnalysisSourceDO weixinArticleAnalysisSourceDO = value.stream().filter(o -> ObjectUtils.isNotEmpty(o.getUserSource()) && o.getUserSource() == 99999999).collect(Collectors.toList()).get(0);
                WeixinArticleAnalysisSaveReqVO saveReqVO = BeanUtils.toBean(weixinArticleAnalysisSourceDO, WeixinArticleAnalysisSaveReqVO.class);
                // 子表数据（userSource不为99999999的数据）
                List<WeixinArticleAnalysisSourceDO> subDOS = value.stream().filter(o -> ObjectUtils.isNotEmpty(o.getUserSource()) && o.getUserSource() != 99999999).collect(Collectors.toList());
                saveReqVO.setWeixinArticleAnalysisSources(subDOS);

                this.createWeixinArticleAnalysis(saveReqVO);
            });
        } catch (Exception e) {
            webinterfaceLogDO.setInterfaceStatus("失败");
            webinterfaceLogDO.setInterfaceErrorInfo(e.getMessage());
            webinterfaceLogMapper.updateById(webinterfaceLogDO);
            logger.error("微信公众号【获取图文统计分时数据】接口失败！", e);
        }
    }

    @Override
    public void syncWeixinArticleUsershare() {
        // 获取微信token
        String weixinToken = appTokenService.getWeixinToken();
        if (StringUtils.isEmpty(weixinToken)) {
            throw exception(WEIXIN_TOKEN_NOT_EXISTS);
        }

        // 接口配置
        String configValue = configService.getConfigValueByKey("weixinConfig");
        if (StringUtils.isEmpty(configValue)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        JSONObject configJo = JSONObject.parseObject(configValue);
        // 接口开关
        String onOff = configJo.getString("onOff");
        if (!"on".equals(onOff)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        // 获取图文分享转发数据地址
        String articleUsershareUrl = configJo.getString("articleUsershareUrl");
        articleUsershareUrl = articleUsershareUrl + "?access_token=" + weixinToken;

        // 构造请求参数（每天查询一次，默认查询前一天数据）
        LocalDate date = LocalDate.now().minusDays(1L);
        JSONObject params = new JSONObject();
        params.put("begin_date", date.toString());
        params.put("end_date", date.toString());

        WebinterfaceLogDO webinterfaceLogDO = new WebinterfaceLogDO();

        try {
            // 初始化图文分享转发数据接口日志数据（默认成功）
            webinterfaceLogDO.setInterfaceSystemName("微信公众号");
            webinterfaceLogDO.setInterfaceName("获取图文分享转发数据");
            webinterfaceLogDO.setInterfaceUrl(articleUsershareUrl);
            webinterfaceLogDO.setInterfaceRequestMethod("POST");
            webinterfaceLogDO.setInterfaceParam(JSONObject.toJSONString(params));
            webinterfaceLogDO.setInterfaceStatus("成功");
            webinterfaceLogMapper.insert(webinterfaceLogDO);

            // 获取图文分享转发数据
            String articleUsershareResult = HttpUtils.post(articleUsershareUrl, new HashMap<>(), JSONObject.toJSONString(params));
            // 解析接口结果
            JSONObject articleUsershareResultJo = JSONObject.parseObject(articleUsershareResult);
            Integer articleUsershareErrcode = articleUsershareResultJo.getInteger("errcode");
            if (ObjectUtils.isNotEmpty(articleUsershareErrcode)) {
                webinterfaceLogDO.setInterfaceStatus("失败");
                webinterfaceLogDO.setInterfaceErrorInfo(articleUsershareResult);
                webinterfaceLogMapper.updateById(webinterfaceLogDO);
                return;
            }
            webinterfaceLogDO.setInterfaceErrorInfo(articleUsershareResult);
            webinterfaceLogMapper.updateById(webinterfaceLogDO);

            // 处理接口数据
            // 子表数据
            JSONArray articleUsershareJa = articleUsershareResultJo.getJSONArray("list");
            List<WeixinArticleAnalysisSourceDO> articleAnalysisSourceDOS = BeanUtils.toBean(articleUsershareJa, WeixinArticleAnalysisSourceDO.class);
            articleAnalysisSourceDOS.forEach(o -> {
                o.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_SHARE.getType());
                o.setDataType(WeixinArticleAnalysisEnum.GET_USER_SHARE.getName());
            });
            // 主表数据
            WeixinArticleAnalysisSaveReqVO saveReqVO = new WeixinArticleAnalysisSaveReqVO();
            saveReqVO.setRefDate(date);
            saveReqVO.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_SHARE.getType());
            saveReqVO.setDataType(WeixinArticleAnalysisEnum.GET_USER_SHARE.getName());
            int shareUser = 0;
            int shareCount = 0;
            if (CollectionUtils.isNotEmpty(articleAnalysisSourceDOS)) {
                shareUser = articleAnalysisSourceDOS.stream().filter(o -> ObjectUtils.isNotEmpty(o.getShareUser()))
                        .map(WeixinArticleAnalysisSourceDO::getShareUser).reduce(0, Integer::sum);
                shareCount = articleAnalysisSourceDOS.stream().filter(o -> ObjectUtils.isNotEmpty(o.getShareCount()))
                        .map(WeixinArticleAnalysisSourceDO::getShareCount).reduce(0, Integer::sum);
            }
            saveReqVO.setShareUser(shareUser);
            saveReqVO.setShareCount(shareCount);
            saveReqVO.setWeixinArticleAnalysisSources(articleAnalysisSourceDOS);

            this.createWeixinArticleAnalysis(saveReqVO);
        } catch (Exception e) {
            webinterfaceLogDO.setInterfaceStatus("失败");
            webinterfaceLogDO.setInterfaceErrorInfo(e.getMessage());
            webinterfaceLogMapper.updateById(webinterfaceLogDO);
            logger.error("微信公众号【获取图文分享转发数据】接口失败！", e);
        }
    }

    @Override
    public void syncWeixinArticleUsersharehour() {
        // 获取微信token
        String weixinToken = appTokenService.getWeixinToken();
        if (StringUtils.isEmpty(weixinToken)) {
            throw exception(WEIXIN_TOKEN_NOT_EXISTS);
        }

        // 接口配置
        String configValue = configService.getConfigValueByKey("weixinConfig");
        if (StringUtils.isEmpty(configValue)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        JSONObject configJo = JSONObject.parseObject(configValue);
        // 接口开关
        String onOff = configJo.getString("onOff");
        if (!"on".equals(onOff)) {
            throw exception(INTERFACE_CONFIG_NOT_EXISTS);
        }

        // 获取图文分享转发分时数据地址
        String articleUsersharehourUrl = configJo.getString("articleUsersharehourUrl");
        articleUsersharehourUrl = articleUsersharehourUrl + "?access_token=" + weixinToken;

        // 构造请求参数（每天查询一次，默认查询前一天数据）
        LocalDate date = LocalDate.now().minusDays(1L);
        JSONObject params = new JSONObject();
        params.put("begin_date", date.toString());
        params.put("end_date", date.toString());

        WebinterfaceLogDO webinterfaceLogDO = new WebinterfaceLogDO();

        try {
            // 初始化图文分享转发分时数据接口日志数据（默认成功）
            webinterfaceLogDO.setInterfaceSystemName("微信公众号");
            webinterfaceLogDO.setInterfaceName("获取图文分享转发分时数据");
            webinterfaceLogDO.setInterfaceUrl(articleUsersharehourUrl);
            webinterfaceLogDO.setInterfaceRequestMethod("POST");
            webinterfaceLogDO.setInterfaceParam(JSONObject.toJSONString(params));
            webinterfaceLogDO.setInterfaceStatus("成功");
            webinterfaceLogMapper.insert(webinterfaceLogDO);

            // 获取图文分享转发分时数据
            String articleUsersharehourResult = HttpUtils.post(articleUsersharehourUrl, new HashMap<>(), JSONObject.toJSONString(params));
            // 解析接口结果
            JSONObject articleUsersharehourResultJo = JSONObject.parseObject(articleUsersharehourResult);
            Integer articleUsersharehourErrcode = articleUsersharehourResultJo.getInteger("errcode");
            if (ObjectUtils.isNotEmpty(articleUsersharehourErrcode)) {
                webinterfaceLogDO.setInterfaceStatus("失败");
                webinterfaceLogDO.setInterfaceErrorInfo(articleUsersharehourResult);
                webinterfaceLogMapper.updateById(webinterfaceLogDO);
                return;
            }
            webinterfaceLogDO.setInterfaceErrorInfo(articleUsersharehourResult);
            webinterfaceLogMapper.updateById(webinterfaceLogDO);

            // 处理接口数据
            JSONArray articleUsersharehourJa = articleUsersharehourResultJo.getJSONArray("list");
            List<WeixinArticleAnalysisSourceDO> articleAnalysisSourceDOS = BeanUtils.toBean(articleUsersharehourJa, WeixinArticleAnalysisSourceDO.class);
            articleAnalysisSourceDOS.forEach(o -> {
                o.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_SHAREHOUR.getType());
                o.setDataType(WeixinArticleAnalysisEnum.GET_USER_SHAREHOUR.getName());
            });
            // 按小时分组
            Map<Integer, List<WeixinArticleAnalysisSourceDO>> listMap = articleAnalysisSourceDOS.stream().collect(Collectors.groupingBy(WeixinArticleAnalysisSourceDO::getRefHour, LinkedHashMap::new, Collectors.toList()));
            listMap.forEach((key, value) -> {
                WeixinArticleAnalysisSaveReqVO saveReqVO = new WeixinArticleAnalysisSaveReqVO();
                saveReqVO.setRefDate(date);
                saveReqVO.setRefHour(key);
                saveReqVO.setDataTypeCode(WeixinArticleAnalysisEnum.GET_USER_SHAREHOUR.getType());
                saveReqVO.setDataType(WeixinArticleAnalysisEnum.GET_USER_SHAREHOUR.getName());
                int shareUser = 0;
                int shareCount = 0;
                if (CollectionUtils.isNotEmpty(value)) {
                    shareUser = value.stream().filter(o -> ObjectUtils.isNotEmpty(o.getShareUser()))
                            .map(WeixinArticleAnalysisSourceDO::getShareUser).reduce(0, Integer::sum);
                    shareCount = value.stream().filter(o -> ObjectUtils.isNotEmpty(o.getShareCount()))
                            .map(WeixinArticleAnalysisSourceDO::getShareCount).reduce(0, Integer::sum);
                }
                saveReqVO.setShareUser(shareUser);
                saveReqVO.setShareCount(shareCount);
                saveReqVO.setWeixinArticleAnalysisSources(value);

                this.createWeixinArticleAnalysis(saveReqVO);
            });
        } catch (Exception e) {
            webinterfaceLogDO.setInterfaceStatus("失败");
            webinterfaceLogDO.setInterfaceErrorInfo(e.getMessage());
            webinterfaceLogMapper.updateById(webinterfaceLogDO);
            logger.error("微信公众号【获取图文分享转发分时数据】接口失败！", e);
        }
    }

    private void createWeixinArticleAnalysisSourceList(Long analysisId, List<WeixinArticleAnalysisSourceDO> list) {
        list.forEach(o -> o.setAnalysisId(analysisId).clean());
        weixinArticleAnalysisSourceMapper.insertBatch(list);
    }

    private void updateWeixinArticleAnalysisSourceList(Long analysisId, List<WeixinArticleAnalysisSourceDO> list) {
	    list.forEach(o -> o.setAnalysisId(analysisId).clean());
	    List<WeixinArticleAnalysisSourceDO> oldList = weixinArticleAnalysisSourceMapper.selectListByAnalysisId(analysisId);
	    List<List<WeixinArticleAnalysisSourceDO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
            boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
            if (same) {
                newVal.setId(oldVal.getId()).clean(); // 解决更新情况下：updateTime 不更新
            }
            return same;
	    });

	    // 第二步，批量添加、修改、删除
	    if (CollUtil.isNotEmpty(diffList.get(0))) {
	        weixinArticleAnalysisSourceMapper.insertBatch(diffList.get(0));
	    }
	    if (CollUtil.isNotEmpty(diffList.get(1))) {
	        weixinArticleAnalysisSourceMapper.updateBatch(diffList.get(1));
	    }
	    if (CollUtil.isNotEmpty(diffList.get(2))) {
	        weixinArticleAnalysisSourceMapper.deleteByIds(convertList(diffList.get(2), WeixinArticleAnalysisSourceDO::getId));
	    }
    }

    private void deleteWeixinArticleAnalysisSourceByAnalysisId(Long analysisId) {
        weixinArticleAnalysisSourceMapper.deleteByAnalysisId(analysisId);
    }

	private void deleteWeixinArticleAnalysisSourceByAnalysisIds(List<Long> analysisIds) {
        weixinArticleAnalysisSourceMapper.deleteByAnalysisIds(analysisIds);
	}

}